#pragma once
#include <cstdint>
#include <cassert>
#include <array>
#include "rotor.hpp"

namespace clay {
    template<std::uint16_t charset_size, std::uint8_t rotors_number>
    class RotorArray {
    private:
        typedef Rotor<charset_size> RotorType;

        std::array<RotorType, rotors_number> rotors;
    public:
        RotorArray() = default;
        RotorArray(const std::array<std::uint8_t, rotors_number>& rotor_shifts)
        {
            static_assert(rotors_number > 0);

            for (std::uint8_t i = 0; i < rotors_number; i++) {
                rotors[i] = RotorType(rotor_shifts[i], i + 1);
            }
        }


        void Roll()
        {
            std::uint8_t carry = 1;

            for (RotorType& rotor : rotors) {
                carry = rotor.Roll(carry);
            }
        }


        std::uint8_t Map(std::uint8_t value) const
        {
            assert(value < charset_size);

            std::for_each(rotors.cbegin(), rotors.cend(),
                [&value](const RotorType& rotor){ value = rotor.Map(value); }
            );

            return value;
        }


        std::uint8_t ReverseMap(std::uint8_t value) const
        {
            assert(value < charset_size);

            std::for_each(rotors.crbegin(), rotors.crend(),
                [&value](const RotorType& rotor){ value = rotor.ReverseMap(value); }
            );

            return value;
        }
    };
}